package chap_01_CompletableFuture.step_04_LockSupport;

import java.util.concurrent.locks.LockSupport;

/**
 * @Description 使用 LockSupport 的 park、unpark 来实现线程的阻塞、唤醒
 * @Author shihan
 * @Date 2022/10/23 11:37
 * @Version 1.0
 */
public class LockSupport_03_LockSupport {

    /**
     * 局限性：仅仅是 park、unpark 必须成对出现，不再有顺序问题（局限性已经降到了最低）；
     * 改进点：
     * --1、不用在 synchronized、ReentrantLock 的 lock、unlock 块中编写；
     * --2、park、unpark 不再有顺序问题，即便先 unpark 后 park，后出现的 park 也依然不会被阻塞，因为前面的 unpark 以及关联了一个许可证；
     * --2.1、这一点是 notify、notifyAll、signal、signalAll 所做不到的，因为他们的唤醒动作都是实时的，过时不候（这就反映了许可证方式的强大）；
     * --强调：
     * --1、虽然 unpark、park 不再有先后顺序问题，但是因为去掉了在同步代码块中执行，所以会出现两个线程同时执行的场景；
     * --2、理论上只要 unpark、park 成对出现，就不会出现阻塞问题（许可证机制）；
     * --3、但是又因为 unpark 不会累加，当同时出现连续执行两次 unpark 时，就会丢失一个许可证，造成阻塞的现象；
     * 注意点：unpark 的时候必须要指明对应的线程，并且注意线程的实例化问题；
     *
     * @param args
     */
    public static void main(String[] args) {
        Thread t1;
        Thread t2;
        Demo3 d1 = new Demo3();
        Demo3 d2 = new Demo3();

        t1 = new Thread(d1, "t1");
        t2 = new Thread(d2, "t2");
        // 这样做其实主要是用来解决 unpark 时的线程设置以及实例化问题
        d1.setUnparkThread(t2);
        d2.setUnparkThread(t1);

        t1.start();

        //【同时注释掉的代码】--part01
        /*try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        t2.start();

    }

}

class Demo3 implements Runnable {

    private Thread unparkThread;

    public void setUnparkThread(Thread unparkThread) {
        this.unparkThread = unparkThread;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName());
            LockSupport.unpark(unparkThread);
            LockSupport.park();
            //【同时注释掉的代码】--part02
            // 这里还在判断的原因是，当前的 park、unpark 不在同步代码块中了，会存在并发操作同时进行，并且主线程里还 sleep 了一段时间
            // 并且 unpark 的许可证不会累加最多一个
            /*if (i != 4) {
                LockSupport.park();
            }*/
        }
    }
}
